package ogmios.components;

import ogmios.core.*;
import ogmios.components.munches.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
import java.io.*;

/**
 * A terminal that will execute commands, taking input and showing output.
 */
public class Terminal extends JPanel implements Context
{
 private final JTextArea text;
 private final JTextArea input;
 private final JLabel currentWorkingDirectoryText;
 private String currentWorkingDirectory="";
 private HistoryIndex<String> history;

 public Terminal()
 {
  super(new BorderLayout());
  text = new JTextArea();
  text.setEditable(false);
  text.setLineWrap(true);
  text.setWrapStyleWord(true);
  input = new JTextArea();
  input.setLineWrap(true);
  input.setWrapStyleWord(true);
  currentWorkingDirectoryText = new JLabel();
  setCurrentWorkingDirectory(System.getProperty("user.home"));
  add(new JScrollPane(text));
  JPanel lowerPanel = new JPanel(new BorderLayout());
  lowerPanel.add(currentWorkingDirectoryText, BorderLayout.WEST);
  lowerPanel.add(new JScrollPane(input));
  add(lowerPanel, BorderLayout.SOUTH);
  InputMap inputInputMap = input.getInputMap(JComponent.WHEN_FOCUSED);
  inputInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "EnterCommand");
  ActionMap inputActionMap = input.getActionMap();
  inputActionMap.put("EnterCommand",
   new AbstractAction()
   {
    public void actionPerformed(ActionEvent e)
    {
     enterCommand();
    }
   }
   );
 inputInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "BackHistory");
 inputActionMap.put("BackHistory", 
   new AbstractAction()
   {
     public void actionPerformed(ActionEvent e)
     {
       if (history.canGoBack())
       {
          if (history.getLastOperation() == HistoryIndex.FORWARD_OPERATION)
          {
            String back = history.goBack();
            input.setText(history.canGoBack() ? history.goBack() :back);
          }
          else
          {
            input.setText(history.goBack());
          }
       }
    }
   }
  );

 inputInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "ForwardHistory");
 inputActionMap.put("ForwardHistory", 
   new AbstractAction()
   {
     public void actionPerformed(ActionEvent e)
     {
         if (history.canGoForward())
         {
           if (history.getLastOperation() == HistoryIndex.BACK_OPERATION)
           {
            history.goForward();
            if (history.canGoForward())
             input.setText(history.goForward());
           }
           else
           {
             input.setText(history.goForward());
          }
         }
      }
   }
  );
  
  history = new HistoryIndex<String>();
 }

 /**
 * Set name, and also prepend name to children's names.
 */
 public void setName(String name)
 {
  super.setName(name);
  input.setName(name + " Input");
  text.setName(name + " Output");
  currentWorkingDirectoryText.setName(name + " Current Working Directory");
 }

 /**
 * Returns the component used to display output
 */
 public JTextComponent getTerminalOutput()
 {
   return text;
 }

 /**
 * Returns the component used to gather input
 */
 public JTextComponent getTerminalInput()
 {
   return input;
 }

 /**
 * Returns the component used to display the current working directory;
 */
 public JComponent getTerminalCurrentWorkingDirectoryLabel()
 {
  return currentWorkingDirectoryText;
 }

 /**
 * Clears and executes input
 */
 public void enterCommand()
 {
  String input=this.input.getText();
  this.input.setEnabled(false);
  this.input.setText("");

  println(currentWorkingDirectoryText.getText() + input);
  history.add(input);
  CommandManager.execute(input, this);
  this.input.setEnabled(true);
  this.input.requestFocus();
 }
 
 public void setFocusToInput()
 {
   input.requestFocus();
 }

 /**
 * Adds input to the input field
 */
 public void enterInput(String input)
 {
  this.input.append(input);
 }

 /**
 * Sets the input field to the given input
 */
 public void replaceInput(String input)
 {
  this.input.setText(input);
 }
 public String getCurrentWorkingDirectory()
 {
  return currentWorkingDirectory;
 }

 public void setCurrentWorkingDirectory(String currentWorkingDirectory)
 {
   File cwd = OgmiosUtilities.resolvedFile(currentWorkingDirectory, this.currentWorkingDirectory);
   if (cwd.exists() && cwd.isDirectory())
   {
    currentWorkingDirectory = cwd.getAbsolutePath();
    this.currentWorkingDirectory = currentWorkingDirectory;
    currentWorkingDirectoryText.setText(currentWorkingDirectory + ">");
   }
 }

 public void print(String output)
 {
  text.append(output);
 }

 public void println(String output)
 {
  text.append(output);
  newLine();
 }
 
 public void newLine()
 {
  text.append("\n");
 }
}